/***************************************************************************************************
  *Copyright(C),2010-2017,Sumscope
  *FileName	:  proto_message.h
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2019/01/18
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
  ***************************************************************************************************/
#ifndef PROTO_MESSAGE_H_52A7DC9B_41D0_4345_BDD3_1A7DD97D9C24
#define PROTO_MESSAGE_H_52A7DC9B_41D0_4345_BDD3_1A7DD97D9C24
#include "core/strings/BaseString.h"
#include "extdef.h"
#include <string>
#include <vector>

#pragma warning(disable:4251)

namespace qb{
	namespace base{
		namespace msg{
			typedef unsigned char       uint8_t;
			typedef signed char         int8_t;
			typedef unsigned short      uint16_t;
			typedef short               int16_t;
			typedef unsigned int        uint32_t;
			typedef int                 int32_t;
			typedef unsigned long long  uint64_t;
			typedef long long           int64_t;

			struct Buffer{
				const char* data;			// 该buffer的起始地址
				int			size;			// 该buffer的内存大小
				int			count;			// 用于检查,该buffer里面有几个值
			public:
				Buffer() :data(nullptr), size(0), count(0){}
				Buffer(const Buffer& buf) :data(buf.data), size(buf.size), count(buf.count){}
				Buffer(const char* d, int s) :data(d), size(s), count(0){}
				Buffer(const char* d, int s, int c) :data(d), size(s), count(c){}
				Buffer& operator = (const Buffer& buf){ data = buf.data; size = buf.size; count = buf.count; return *this; }
				bool operator!=(const Buffer& buf)const{ return data != buf.data || size != buf.size || count != buf.count; }
				bool operator==(const Buffer& buf)const{ return data == buf.data && size == buf.size && count == buf.count; }
				const char* end()const{ return data + size; }
			};
			class Raw{
			public:
				const void * Data;
				uint32_t Length;

				Raw() :Data(nullptr), Length(0){}
				Raw(const Raw& raw) :Data(raw.Data), Length(raw.Length){}
				Raw(const char* d, int len) :Data(d), Length(len){}
				~Raw(){}

				bool Copy(const Raw& raw);
				bool Copy(const void * buffer, size_t buflen);

				void Ref(const Raw& raw);
				void Clear();

				Raw& operator=(const Raw& raw)
				{
					Data = raw.Data;
					Length = raw.Length;
					return *this;
				}
				inline bool Owned() const { return owned_; }
			private:
				bool owned_;       //是否由这个类自动释放。
			};
			class Message;
			class SSPROTOAPI Value{
			public:
				enum VarType : uint8_t{//注意:此字段内容必须与ss::proto::Variant里的定义值一致

					VAR_UNKNOWN = 0,
					VAR_VOID = VAR_UNKNOWN,

					VAR_BOOL = 1,

					VAR_INT8 = 2,
					VAR_UINT8 = 3,

					VAR_INT16 = 4,
					VAR_UINT16 = 5,
					VAR_INT32 = 6,
					VAR_UINT32 = 7,
					VAR_INT64 = 8,
					VAR_UINT64 = 9,

					VAR_FLOAT = 10,
					VAR_DOUBLE = 11,

					VAR_STRING = 12,        //str16
					VAR_RAW = 13,        //vbin32

					VAR_MAP = 14,        //map
					VAR_LIST = 15          //list
				};

			public:						// 设计为40字节一个节点
				Message*	msg;		// 指向其拥有者Message的指针
				uint8_t		Type;		// 当前节点类型,适配,ss::proto::Variant::VarType值
				uint8_t		ptype;		// 父亲节点类型,可能为空,list,map
				uint8_t		keylen;		// 当父节点为map时,指key的长度,没有0结尾
				uint8_t		level;		// 用于调试,0表示顶级节点
				int			bytes;		// 该值占据的总字节大小
				int			size;		// 该值的实际内容编码长度,排除type,tag,len,count
				int			count;		// 子节点个数,只有当list/map,此值才可能不为0
				const char*	key;		// 当ptype为map的时候,此值表示对应的key
				const char* data;		// 该值的实际指针,保证从data到data+size是有效的
				Buffer		parent;		// 父亲节点的内容区
			public:
				Value() :msg(nullptr), Type(0), level(0), ptype(0), keylen(0),
					bytes(0), size(0), count(0), key(nullptr), data(nullptr){}
				bool operator!=(const Value& v)const{
					return msg != v.msg || data != v.data || Type != v.Type || size != v.size;
				}
				const char* start()const{ return data - (bytes - size); }
				const char* next()const{ return data + size; }
				std::string tostring()const;//仅供调试用
				std::string GetKey()const{ return key ? std::string(key, keylen):std::string(""); }
				std::string GetString()const;
				bool GetInt32(int& value)const;
				bool GetDouble(double& value)const;
				bool RefString(const char *& value, size_t &size) const;

#define DECLEAR_OPERATOR(TYPE)	operator TYPE()const;
				DECLEAR_OPERATOR(bool);
				DECLEAR_OPERATOR(uint8_t);
				DECLEAR_OPERATOR(uint16_t);
				DECLEAR_OPERATOR(uint32_t);
				DECLEAR_OPERATOR(uint64_t);
				DECLEAR_OPERATOR(int8_t);
				DECLEAR_OPERATOR(int16_t);
				DECLEAR_OPERATOR(int32_t);
				DECLEAR_OPERATOR(int64_t);
				DECLEAR_OPERATOR(float);
				DECLEAR_OPERATOR(double);
			};
			class SSPROTOAPI ValueDict{
				typedef unsigned int uint;
				typedef unsigned short ushort;
				/*
				QB收到的字典数据包中的数据类型编码,目前只用到int32,string,double,time32四种类型
				*/
			public:
				enum kPackDateType{
					kPackDateTypeNone = 0,
					kPackDateTypeInt8 = 1,
					kPackDateTypeUInt8 = 2,
					kPackDateTypeInt16 = 3,
					kPackDateTypeUInt16 = 4,
					kPackDateTypeInt32 = 5,
					kPackDateTypeUint32 = 6,
					kPackDateTypeInt64 = 7,
					kPackDateTypeUInt64 = 8,
					kPackDateTypeBool = 9,
					kPackDateTypeString = 10,
					kPackDateTypeFloat = 11,
					kPackDateTypeDouble = 12,
					kPackDateTypeRaw = 13,
					kPackDateTypeTime32 = 14,	//等同于time_t，精度秒
					kPackDateTypeTime64 = 15,	//等同于time_t + 毫秒，精度毫秒
					kPackDateTypeCount = 16
				};
				struct Field{
					kPackDateType type;
					int			len;
					int			col, row;
					const char* data;
					const char*	name;
				};
			protected:
				struct PackHeader{						// 更新包中的数据头部
					uint	tag;						// 文件开头的4个字节,0x44425253
					uint	StartPos;					// 记录开始的偏移量
					uint	RecordCount;				// 记录个数
					ushort	FieldCount;					// 每条记录的字段个数
				};
				std::vector<const char*>		m_fields;
				std::vector<Field>			m_values;
				PackHeader				m_head;
				char*					m_buffer;
				int						m_capcity;
				int						m_packsize;		// 解压后的大小
			public:
				ValueDict();
				~ValueDict();
				bool Parse(const char* data, int len);
				int GetRowCount()const{ return m_head.RecordCount; }
				int GetColCount()const{ return m_head.FieldCount; }
				bool GetValue(int row,int col,Field& value)const;
				const char* GetColName(int col)const;
				int GetSize()const{ return m_packsize; }
				const char* GetBuffer()const{ return m_buffer; }
			protected:
				bool IsValidDict(const PackHeader& head, const char* start, int nfield);

			};
			class  SSPROTOAPI ValueList{
			public:
				class SSPROTOAPI const_iterator {
				protected:
					Buffer		m_scope;		// 当前枚举器的范围
					Value		m_value;		// 当前枚举到的值
					int			m_index;		// 当前枚举器位于m_scope的第几个
				public:
					
				public:
					const_iterator() :m_index(-1){}
					const_iterator(const Buffer& buf, const Value& v, int i) :m_scope(buf), m_value(v), m_index(0){}
					inline int index()const{ return m_index; }
					inline int size()const{ return m_scope.count; }
					const_iterator& operator=(const const_iterator& iter)
					{
						m_scope = iter.m_scope;
						m_value = iter.m_value;
						m_index = iter.m_index;
						return *this;
					}
					const_iterator(const const_iterator& iter){
						m_scope = iter.m_scope;
						m_value = iter.m_value;
						m_index = iter.m_index;
					}
					inline const Value* operator->()const{return &m_value;}
					inline bool operator!=(const const_iterator& iter) const{
						return m_index != iter.m_index || m_scope != iter.m_scope ||
							m_value != iter.m_value;
					}
					inline const Value& operator*() const{ return m_value; }
					const const_iterator& operator++();
				};
			protected:
				Value			m_value;
				const_iterator	m_end;
			public:
				ValueList(){}
				ValueList(const Value& v) :m_value(v){}
				const Value& value()const{ return m_value; }
				int size()const{ return m_value.count; }
				const_iterator begin()const;
				const const_iterator& end()const{ return m_end; }
				void print(int level = 0)const;
				operator const Value& ()const{ return m_value; }
			};
			
			class SSPROTOAPI ValueMap : public ValueList{
			public:
				ValueMap(const Value& v) :ValueList(v){}
				ValueMap(){}
				bool find(const char* name, Value& v)const;

#define VALUEMAP_GET(NAME,VAL) {Value v;if (find(NAME,v)){VAL=v;return true;}return false;}
				bool GetBool(const char *name, bool &value) const{ VALUEMAP_GET(name, value); }
				bool GetUInt8(const char *name, uint8_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetUInt16(const char *name, uint16_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetUInt32(const char *name, uint32_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetUInt64(const char *name, uint64_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetInt8(const char *name, int8_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetInt16(const char *name, int16_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetInt32(const char *name, int32_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetInt64(const char *name, int64_t &value) const{ VALUEMAP_GET(name, value); }
				bool GetFloat(const char *name, float &value) const{ VALUEMAP_GET(name, value); }
				bool GetDouble(const char *name, double &value) const{ VALUEMAP_GET(name, value); }
				bool GetString(const char* name, const char*& value, size_t& size)const;
				bool GetMap(const char* name, ValueMap& vmap)const;
				bool GetList(const char* name, ValueList& vlist)const;
				bool GetRaw(const char *name, Raw& value) const;
			};
#pragma warning(push)
#pragma warning(disable:4251)
			class FieldTable{
			public:
				enum kFindType{
					kFindTypeFail=0,
					kFindTypeByOrder=1,
					kFindTypeByBinary=2
				};
				enum{ kMaxFieldCount = 64 };		// 当一个map下面的字段小于64个,那么使用栈内存
				typedef Buffer Signature;
				typedef qb::base::StackArray<Value, kMaxFieldCount> ValueArray;
				static int CompByKey(const void * p1, const void * p2);
				static int CompString(const char* s1, int len1, const char* s2, int len2);
			private:
				Signature	m_signature;		// 绑定当前的哪一个ValueMap
				Value		m_search;			// 当前二分法搜索的key
				ValueArray	m_values;			// 栈/堆上放置的解析好的当前map的值数组
				int			m_lastpos;			// 上一次搜索的位置,按照顺序获取,性能最佳
			public:
				FieldTable();
				void rebuild(const ValueMap& map);
				const Buffer& buffer()const{ return m_signature; }
				bool getFieldValue(int index, Value& v)const;
				kFindType getFieldValue(const char* name, int len, Value& v) const;
				int  size()const{ return m_values.size(); }
			};
#pragma warning(pop)
			class SSPROTOAPI Message{
				friend class ValueMap;
				FieldTable	m_field_table;	// 任何时候都有且只有一个字段表,需要的时候重建
				ValueMap	m_header;		// 头部
				ValueMap	m_map;			// body
				int			m_bfind;		//
				int			m_sfind;		//
			private:
				Message(const Message& msg) = delete;
				Message& operator=(const Message& msg) = delete;
			public:
				Message();
				~Message();
				void Clear();
				int decode(const char* buf, int len);
				int decodeMap(const char* buf, int len,bool inMap);
				const ValueMap& MapValue()const{ return m_map; }
				const ValueMap& Header()const{ return m_header; }
				static bool DecodeValue(const Buffer& buf, bool inMap, Value& v, bool skipType = false);
			public:
				bool GetBool(const char *name, bool &value) const{ return m_map.GetBool(name, value); }
				bool GetUInt8(const char *name, uint8_t &value) const{ return m_map.GetUInt8(name, value); }
				bool GetUInt16(const char *name, uint16_t &value) const{ return m_map.GetUInt16(name, value); }
				bool GetUInt32(const char *name, uint32_t &value) const{ return m_map.GetUInt32(name, value); }
				bool GetUInt64(const char *name, uint64_t &value) const{ return m_map.GetUInt64(name, value); }
				bool GetInt8(const char *name, int8_t &value) const{ return m_map.GetInt8(name, value); }
				bool GetInt16(const char *name, int16_t &value) const{ return m_map.GetInt16(name, value); }
				bool GetInt32(const char *name, int32_t &value) const{ return m_map.GetInt32(name, value); }
				bool GetInt64(const char *name, int64_t &value) const{ return m_map.GetInt64(name, value); }
				bool GetFloat(const char *name, float &value) const{ return m_map.GetFloat(name, value); }
				bool GetDouble(const char *name, double &value) const{ return m_map.GetDouble(name, value); }

			public://debug
				void print()const;
			protected:
				bool find(const char* name, const ValueMap& map, Value& v);
			};

			class SSPROTOAPI ProtoList{
			public:
				friend class ProtoMap;
				friend class ProtoMessage;
				typedef ValueList::const_iterator const_iterator;
			private:
				ValueList	m_list;
			private:
				ProtoList(const ProtoList& pm) = delete;
				ProtoList& operator=(const ProtoList& pm) = delete;
				void SetList(const Value& list){ m_list = list; }
			public:
				ProtoList(){}
				ProtoList(const Value& v) :m_list(v){}
				const_iterator begin()const{ return m_list.begin(); }
				const_iterator end()const{ return m_list.end(); }
				int size()const{ return m_list.size(); }
				void clear(){ m_list = ValueList(); }
				const ValueList& value()const{ return m_list; }
			};
			class SSPROTOAPI ProtoMap{
			public:
				friend class ProtoMessage;
				typedef ValueList::const_iterator const_iterator;
			private:
				ValueMap			m_map;
				std::vector<ProtoList*>	m_reflist;
			private:
				ProtoMap(const ProtoMap& pm) = delete;
				ProtoMap& operator=(const ProtoMap& pm) = delete;
				void SetMap(const Value& v){ m_map = v; }
			public:
				ProtoMap(){}
				ProtoMap(const Value& v) :m_map(v){}
				ProtoMap(const ValueMap& vmap) :m_map(vmap){}
				~ProtoMap(){}
				const_iterator begin()const{ return m_map.begin(); }
				const_iterator end()const{ return m_map.end(); }
				bool RefList(const char* name, const ProtoList*& pList)const;
				bool RefMapFrom(const Message& msg, const char* name);
				bool GetList(const char* name, ProtoList& list)const;
				bool getList(const char* name, ProtoList& list)const{ return GetList(name, list); }
				bool GetMap(const char* name, ProtoMap& map)const;
				bool RefString(const char *name, const char *& value, size_t &size) const;
				bool GetRaw(const char *name, Raw& value) const;
				operator const ValueMap&()const{ return m_map; }

				bool GetBool(const char *name, bool &value) const{ return m_map.GetBool(name, value); }
				bool GetUInt8(const char *name, uint8_t &value) const{ return m_map.GetUInt8(name, value); }
				bool GetUInt16(const char *name, uint16_t &value) const{ return m_map.GetUInt16(name, value); }
				bool GetUInt32(const char *name, uint32_t &value) const{ return m_map.GetUInt32(name, value); }
				bool GetUInt64(const char *name, uint64_t &value) const{ return m_map.GetUInt64(name, value); }
				bool GetInt8(const char *name, int8_t &value) const{ return m_map.GetInt8(name, value); }
				bool GetInt16(const char *name, int16_t &value) const{ return m_map.GetInt16(name, value); }
				bool GetInt32(const char *name, int32_t &value) const{ return m_map.GetInt32(name, value); }
				bool GetInt64(const char *name, int64_t &value) const{ return m_map.GetInt64(name, value); }
				bool GetFloat(const char *name, float &value) const{ return m_map.GetFloat(name, value); }
				bool GetDouble(const char *name, double &value) const{ return m_map.GetDouble(name, value); }


				inline bool getBool(const std::string& name, bool &value) const { return GetBool(name.c_str(), value); }
				inline bool getUint8(const std::string& name, uint8_t &value) const { return GetUInt8(name.c_str(), value); }
				inline bool getUint16(const std::string& name, uint16_t &value) const { return GetUInt16(name.c_str(), value); }
				inline bool getUint32(const std::string& name, uint32_t &value) const { return GetUInt32(name.c_str(), value); }
				inline bool getUint64(const std::string& name, uint64_t &value) const { return GetUInt64(name.c_str(), value); }
				inline bool getInt8(const std::string& name, int8_t &value) const { return GetInt8(name.c_str(), value); }
				inline bool getInt16(const std::string& name, int16_t &value) const { return GetInt16(name.c_str(), value); }
				inline bool getInt32(const std::string& name, int32_t &value) const { return GetInt32(name.c_str(), value); }
				inline bool getInt64(const std::string& name, int64_t &value) const { return GetInt64(name.c_str(), value); }
				inline bool getFloat(const std::string& name, float &value) const { return GetFloat(name.c_str(), value); }
				inline bool getDouble(const std::string& name, double &value) const { return GetDouble(name.c_str(), value); }
			};
			class IRawParser{
			public:
				enum kExpectType{
					kExpectTypeNull,		// 默认值
					kExpectTypeString,		// 字符串
					kExpectTypeDouble,		// 双精度浮点数
					kExpectTypeInt,			// 整数:变长无符号64位整数
					kExpectTypeMax
				};
				virtual bool Parse(const char* data, int length) = 0;
				virtual int  GetRow()const = 0;
				virtual int  GetCol()const = 0;
				virtual const char* GetColName(int col)const = 0;
				virtual kExpectType GetColType(int col)const = 0;
				virtual bool IsCellDefault(int row, int col)const = 0;
				virtual bool GetCellValue(int row, int col, double& value) = 0;
				virtual bool GetCellValue(int row, int col, int64_t& value) = 0;
				virtual bool GetCellValue(int row, int col, const char*& value, int& len) = 0;
			};
			class SSPROTOAPI ProtoMessage{
				Message		m_msg;
			public:
				ProtoMessage();
				ProtoMessage(const ProtoMap& map);
				bool GetList(const char* name, ProtoList& list)const;
				const ValueMap& MapValue()const{ return m_msg.MapValue(); }
				const ValueMap& HeadValue()const{ return m_msg.Header(); }
				bool GetRaw(const char *name, Raw& value) const
				{
					return m_msg.MapValue().GetRaw(name, value);
				}
				int GetAllKeySize();
				int ToJson(std::string& str);
				int ToJson(std::string& str,IRawParser* rawParser);
				void Dump(int id);
#define PROTOMSG_GET(NAME,VAL,FUNC) return m_msg.MapValue().FUNC(NAME,VAL);
				bool getList(const char* name, ProtoList& list)const{
					ValueList v;
					if (m_msg.MapValue().GetList(name, v))
					{
						list.SetList(v);
						return true;
					}
					return false;
				}
				bool GetMap(const char* name, ProtoMap& map)const{
					ValueMap v;
					if (m_msg.MapValue().GetMap(name, v))
					{
						map.SetMap(v);
						return true;
					}
					return false;
				}
				bool RefString(const char *name, const char *& value, size_t &size) const
				{
					return m_msg.MapValue().GetString(name, value, size);
				}

				bool GetBool(const char *name, bool &value) const{ PROTOMSG_GET(name, value, GetBool); }
				bool GetUInt8(const char *name, uint8_t &value) const{ PROTOMSG_GET(name, value, GetUInt8); }
				bool GetUInt16(const char *name, uint16_t &value) const{ PROTOMSG_GET(name, value, GetUInt16); }
				bool GetUInt32(const char *name, uint32_t &value) const{ PROTOMSG_GET(name, value, GetUInt32); }
				bool GetUInt64(const char *name, uint64_t &value) const{ PROTOMSG_GET(name, value, GetUInt64); }
				bool GetInt8(const char *name, int8_t &value) const{ PROTOMSG_GET(name, value, GetInt8); }
				bool GetInt16(const char *name, int16_t &value) const{ PROTOMSG_GET(name, value, GetInt16); }
				bool GetInt32(const char *name, int32_t &value) const{ PROTOMSG_GET(name, value, GetInt32); }
				bool GetInt64(const char *name, int64_t &value) const{ PROTOMSG_GET(name, value, GetInt64); }
				bool GetFloat(const char *name, float &value) const{ PROTOMSG_GET(name, value, GetFloat); }
				bool GetDouble(const char *name, double &value) const{ PROTOMSG_GET(name, value, GetDouble); }
				inline bool getBool(const std::string& name, bool &value) const { return GetBool(name.c_str(), value); }
				inline bool getUint8(const std::string& name, uint8_t &value) const { return GetUInt8(name.c_str(), value); }
				inline bool getUint16(const std::string& name, uint16_t &value) const { return GetUInt16(name.c_str(), value); }
				inline bool getUint32(const std::string& name, uint32_t &value) const { return GetUInt32(name.c_str(), value); }
				inline bool getUint64(const std::string& name, uint64_t &value) const { return GetUInt64(name.c_str(), value); }
				inline bool getInt8(const std::string& name, int8_t &value) const { return GetInt8(name.c_str(), value); }
				inline bool getInt16(const std::string& name, int16_t &value) const { return GetInt16(name.c_str(), value); }
				inline bool getInt32(const std::string& name, int32_t &value) const { return GetInt32(name.c_str(), value); }
				inline bool getInt64(const std::string& name, int64_t &value) const { return GetInt64(name.c_str(), value); }
				inline bool getFloat(const std::string& name, float &value) const { return GetFloat(name.c_str(), value); }
				inline bool getDouble(const std::string& name, double &value) const { return GetDouble(name.c_str(), value); }

				std::string GetType()const;
				std::string getType()const;
				std::string GetMessageID()const;
				std::string getMessageID()const;
				std::string GetSubject()const;
				std::string getSubject()const;
				void Clear();
				int decode(const char* buf, int len);
			};
		}
	}//namespace qb;
}

#endif
